#!/usr/bin/python
#-*- coding: utf-8 -*-

"""
description	:2013 ComputerVision Schwanecke Uebungsblatt 02, Homography
date			:20131023
version		:1.0

tested on       :
                Distributor ID:	Ubuntu
                Description:	Ubuntu 12.04.3 LTS
                Release:	12.04
                Codename:	precise
python_version	:Python 2.7.3

usage		:python homography.py imagefile

"""
import sys
import pprint as pp
import collections
import numpy as np
import cv2

PIC_NAME = ''
IMG_ORIG = []
COLOR = (0,0,255)
points = []


def file_to_image(files # list of filenames
                 ):
    """Liste von Dateinamen -> Liste von cv2.imread(CV_LOAD_IMAGE_COLOR) images"""

    images = []
    for f in files:
        images.append(cv2.imread(f, cv2.CV_LOAD_IMAGE_COLOR))
    return images

    
def show(img, # numpyarray
         windowname # unique string
         ):
    """Zeigt ein cv2-image in einem neue Fenster an"""
    
    cv2.namedWindow(windowname, cv2.CV_WINDOW_AUTOSIZE)
    cv2.imshow(windowname, img)


def draw_line(window, image, a, b, color=COLOR):
    """Zeichnet eine Linie zwischen den Pixeln a,b"""

    cv2.line(image, a, b, COLOR)

    # Bild neu zeichnen im window
    cv2.imshow(window, image)


def get_bbox(points):
    """Berrechnet Boundingbox einer 2D-Punktliste"""
    # numpy array draus machen
    points = np.array(points)
    
    # Teile in 2 Haelften entlang Achse 1 (Y)
    split = np.split(points, 2, 1)
    
    x_vals = split[0]
    y_vals = split[1]

    x_min, x_max = min(x_vals), max(x_vals)
    y_min, y_max = min(y_vals), max(y_vals)

    return [(x_min, y_min),(x_max, y_max)]

    
def sort_vertices(vertices # len==4
                  ):
    """Sortiert 4 2D Punktkoordinaten \
    -> [upper_left, upper_right, lower_right, lower_left]

    """
    
    # [obere Eckpunkte, untere Eckp]
    x = lambda k: k[0]
    y = lambda k: k[1]
    sort = sorted(vertices, key=y) 

    # x-Werte definieren links und rechts
    upper, lower = sorted(sort[:2], key=x), sorted(sort[2:], key=x)
    upper_left, upper_right = upper[0], upper[1] 
    lower_left, lower_right = lower[0], lower[1] 

    return [upper_left, upper_right, lower_right, lower_left]


def perspective_transform(img,
                          four_vertices, # shape==(4,2)
                          width=None,
                          height=None
                          ):
    """Fuehrt eine perspektivische Transformation anhand von \
    4 Referenzpunkten durch.

    """
    if width==None and height==None:
        bb = get_bbox(four_vertices)
        width = bb[1][0] - bb[0][0]
        height = bb[1][1] - bb[0][1]

    # wichtig, sonst fehler beim Mapping
    sorted_vertices = sort_vertices(four_vertices)
        
    # src-image in float numpy-array konvertieren
    sorted_vertices = np.array(sorted_vertices, np.float32)
    
    dst = np.array([ [0,0],[width,0],[width,height],[0,height] ],np.float32)
    matrix = cv2.getPerspectiveTransform(sorted_vertices, dst)
    warp = cv2.warpPerspective(IMG_ORIG, matrix, (width,height))

    name = "homography"
    show(warp, name)
    cv2.setMouseCallback(name, mouse_two)

   
# Maus-Callback function
def mouse_one(event, x, y, flags, param):
    """Callback-Funktion fuer Mouseevents"""
    
    if event == cv2.EVENT_LBUTTONDOWN:
        length = len(points)+1

        if length<5:
            # Klickpos rot markieren
            cv2.circle(image,(x,y),10,COLOR,-1)
            points.append((x,y))            
            cv2.imshow(PIC_NAME,image)

            # Linien einzeichnen
            if length==2:
                draw_line(PIC_NAME, image, *points[:2])
            elif length==3:
                draw_line(PIC_NAME, image, *points[1:3])
            elif length==4:
                draw_line(PIC_NAME, image, *points[2:4])
                draw_line(PIC_NAME, image, points[0], points[3])            
                # Ausschnitt anzeigen
                h, w, c = IMG_ORIG.shape # ! erst height                
                perspective_transform(image, points, w, h)

    # quit App mit Rechter Maustaste
    if event == cv2.EVENT_MBUTTONDOWN:        
        cv2.destroyAllWindows()
        sys.exit(1)        

    
# Maus-Callback function
def mouse_two(event, x, y, flags, param):
    """Callback-Funktion fuer Mouseevents"""
    # quit App mit Rechter Maustaste
    if event == cv2.EVENT_MBUTTONDOWN:        
        cv2.destroyAllWindows()
        sys.exit(1)

        
if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "--> usage: python homography.py imagefile"
        sys.exit(0)
        
    PIC_NAME = sys.argv[1]
    # Bild einlesen
    IMG_ORIG = file_to_image([PIC_NAME])[0]
    image = IMG_ORIG.copy()
    
    # Bild anzeigen in HighGUI Window
    show(image, PIC_NAME)

    # Maus callback registrieren
    cv2.setMouseCallback(PIC_NAME, mouse_one)
    
    # Grauwerte Bilineaer interpolieren Fktn suchen
        
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    



    

